/*
 ============================================================================
 Name		: Area.cpp
 Author	  : Lenka Litvova
 Version	 : 1.0
 Copyright   : Your copyright notice
 Description : CArea implementation
 ============================================================================
 */

#include "Area.h"
#include <FBS.H> //TBitmapUtil header file
#include <BITDEV.H> //for drawing on bitmap 

CArea::CArea()
	{
	// No implementation required
	}

CArea::~CArea()
	{
		delete iBorders_left;
		delete iBorders_right;
	}

CArea* CArea::NewLC(TPoint aBegin, TInt aHeight)
	{
	CArea* self = new (ELeave) CArea();
	CleanupStack::PushL(self);
	self->ConstructL(aBegin, aHeight);
	return self;
	}

CArea* CArea::NewL(TPoint aBegin, TInt aHeight)
	{
	CArea* self = CArea::NewLC(aBegin, aHeight);
	CleanupStack::Pop(); // self;
	return self;
	}

void CArea::ConstructL(TPoint aBegin, TInt aHeight)
	{
		iTop_from = aBegin;
	    iTop_to = aBegin;
	    iBottom_from = aBegin;
	    iBottom_to = aBegin;
	    iLeft = aBegin;
	    iRight = aBegin;
	    iSize = 1;
	    iBorders_left = new (ELeave) RHashMap<TInt, TPoint>;
	    iBorders_right = new (ELeave) RHashMap<TInt, TPoint>;
	    iBorders_left->Insert(aBegin.iY, aBegin);
	    iBorders_right->Insert(aBegin.iY, aBegin);
	}

void CArea::Update(TPoint aPoint)
	{
	if(aPoint.iX < iLeft.iX)
		iLeft = aPoint;
    if(aPoint.iX > iRight.iX)
	    iRight = aPoint;
	if(aPoint.iY < iTop_from.iY)
	{
		iTop_from = aPoint;
	    iTop_to = aPoint;
	}
	else if(aPoint.iY == iTop_from.iY)
	{
		if(aPoint.iX < iTop_from.iX)
			iTop_from = aPoint;
	    if(aPoint.iX > aPoint.iX)
	        iTop_to = aPoint;
	}
	if(aPoint.iY > iBottom_from.iY)
	{	            
		iBottom_from = aPoint;
	    iBottom_to = aPoint;
	}
	else if(aPoint.iY == iBottom_from.iY)
	{
		if(aPoint.iX< iBottom_from.iX)
			iBottom_from = aPoint;
	    if(aPoint.iX > iBottom_to.iX)
	        iBottom_to = aPoint;
	}

	TPoint *l = iBorders_left->Find(aPoint.iY);
	if(!l || l->iX > aPoint.iX)
	{
		iBorders_left->Insert(aPoint.iY, aPoint);
	}

	TPoint *r = iBorders_right->Find(aPoint.iY);
	if(!r || r->iX < aPoint.iX)
	{
		iBorders_right->Insert(aPoint.iY, aPoint);
	}
	
	iSize++;
	}

void CArea::Finish()
	{
		iTop = TPoint(iTop_from.iX+((iTop_to.iX-iTop_from.iX)/2), iTop_from.iY);
	    iBottom = TPoint(iBottom_from.iX+((iBottom_to.iX-iBottom_from.iX)/2), iBottom_from.iY);
	}

void CArea::Merge(CArea *aArea)
	{
		if(aArea->iBottom_from.iY > iBottom_from.iY)
	    {
	            iBottom_from = aArea->iBottom_from;
	            iBottom_to = aArea->iBottom_to;
	    }
	    else
	    {
			if(aArea->iBottom_from.iY == iBottom_from.iY && aArea->iBottom_from.iX  < iBottom_from.iX )
	                iBottom_from = aArea->iBottom_from;
	        if(aArea->iBottom_to.iY == iBottom_to.iY && aArea->iBottom_to.iX > iBottom_to.iX )
	                iBottom_to = aArea->iBottom_to;
	    }
	    if(aArea->iTop_from.iY < iTop_from.iY)
	    {
	        iTop_from = aArea->iTop_from;
	        iTop_to = aArea->iTop_to;
	    }
	    else
	    {
			if(aArea->iTop_from.iY == iTop_from.iY && aArea->iTop_from.iX < iTop_from.iX)
				iTop_from = aArea->iTop_from;
	        if(aArea->iTop_to.iY == iTop_to.iY && aArea->iTop_to.iX > iTop_to.iX)
	          	iTop_to = aArea->iTop_to;
	    }
	    if(aArea->GetLeft().iX< iLeft.iX)
	    	iLeft = aArea->GetLeft();
	    if(aArea->GetRight().iX  > iRight.iX )
	        iRight = aArea->GetRight();

	    RHashMap<TInt, TPoint> *left = aArea->GetBordersLeft();
	    RHashMap<TInt, TPoint> *right = aArea->GetBordersLeft();
	    for(TInt i=0 ; i< iBorders_left->Count(); i++)
	    {
			TPoint p_left, p_right;
			TRAPD(err1 , p_left = left->FindL(i));
			TRAPD(err2 , p_right = right->FindL(i));
			
			TPoint *l,*r;
			if(!err1)
			{
				l = iBorders_left->Find(p_left.iY);
				if(!l || l->iX > p_left.iX)
				{
					iBorders_left->Insert(p_left.iY, p_left);
				}
			}

			if(!err2)
			{
				r = iBorders_right->Find(p_right.iY);
				if(!r || r->iX < p_right.iX)
				{
					iBorders_right->Insert(p_right.iY, p_right);
				}
			}    
			
			if(!((!err1 && l && l->iX < p_left.iX) && (!err2 && r && r->iX > p_right.iX)))
	        	iSize++;
	    }
	}

void CArea::ClearBorder(CFbsBitmap *aImage, TRgb aClearColor)
	{
		TSize imageSize = aImage->SizeInPixels();
		TBitmapUtil util(aImage);
		util.Begin(TPoint(0,0));
	
		for(TInt i=3 ; i< iBorders_left->Count()-2; i++)
		{
			TPoint l,r;
			TRAPD(err1, l = iBorders_left->FindL(i));
			TRAPD(err2, r = iBorders_right->FindL(i));
			if(!err1)
			{
				if(l.iX > 2 && l.iX < imageSize.iWidth-2)
				{
					util.SetPos(TPoint(l.iX-2, l.iY));
					util.SetPixel(aClearColor.Value());
					util.SetPos(TPoint(l.iX-1, l.iY));
					util.SetPixel(aClearColor.Value());
					util.SetPos(TPoint(l.iX, l.iY));
					util.SetPixel(aClearColor.Value());
					util.SetPos(TPoint(l.iX+1, l.iY));
					util.SetPixel(aClearColor.Value());
					util.SetPos(TPoint(l.iX+2, l.iY));
					util.SetPixel(aClearColor.Value());
				}
			}
			
			if(!err2)
			{
				if(r.iX > 2 && r.iX < imageSize.iWidth-2)
				{
					util.SetPos(TPoint(r.iX-2, r.iY));
					util.SetPixel(aClearColor.Value());
					util.SetPos(TPoint(r.iX-1, r.iY));
					util.SetPixel(aClearColor.Value());
					util.SetPos(TPoint(r.iX, r.iY));
					util.SetPixel(aClearColor.Value());
					util.SetPos(TPoint(r.iX+1, r.iY));
					util.SetPixel(aClearColor.Value());
					util.SetPos(TPoint(r.iX+2, r.iY));
					util.SetPixel(aClearColor.Value());
				}
			}
		}
		util.End();
	}

void CArea::ClearBorderCV(CNokiaCVImage *aImage, TRgb aClearColor)
	{
		TSize imageSize = aImage->Size();
		CPixelAccess *pa = CPixelAccess::NewLC(aImage);
	
		for(TInt i=3 ; i< iBorders_left->Count()-2; i++)
		{
			TPoint l,r;
			TRAPD(err1, l = iBorders_left->FindL(i));
			TRAPD(err2, r = iBorders_right->FindL(i));
			
			if(!err1)
			{
				if(l.iX > 2 && l.iX < imageSize.iWidth-2)
				{
					pa->SetPos(TPoint(l.iX-2, l.iY));
					pa->SetPixel(aClearColor.Value());
					pa->SetPos(TPoint(l.iX-1, l.iY));
					pa->SetPixel(aClearColor.Value());
					pa->SetPos(TPoint(l.iX, l.iY));
					pa->SetPixel(aClearColor.Value());
					pa->SetPos(TPoint(l.iX+1, l.iY));
					pa->SetPixel(aClearColor.Value());
					pa->SetPos(TPoint(l.iX+2, l.iY));
					pa->SetPixel(aClearColor.Value());
				}
			}
			
			if(!err2)
			{
				if(r.iX > 2 && r.iX < imageSize.iWidth-2)
				{
					pa->SetPos(TPoint(r.iX-2, r.iY));
					pa->SetPixel(aClearColor.Value());
					pa->SetPos(TPoint(r.iX-1, r.iY));
					pa->SetPixel(aClearColor.Value());
					pa->SetPos(TPoint(r.iX, r.iY));
					pa->SetPixel(aClearColor.Value());
					pa->SetPos(TPoint(r.iX+1, r.iY));
					pa->SetPixel(aClearColor.Value());
					pa->SetPos(TPoint(r.iX+2, r.iY));
					pa->SetPixel(aClearColor.Value());
				}
			}
		}
	}


void CArea::Equalize()
	{
		TPoint p; 
		TRAPD(err1, p = GetLeftBorderL(iRight.iY));
	    if(!err1 && iLeft.iX < p.iX  && (Abs(iLeft.iY - (iTop.iY+((iBottom.iY - iTop.iY)/2)))) > Abs(((p.iY - (iTop.iY+((iBottom.iY - iTop.iY)/2))))) )
	    {
			iLeft = p;
	    }
	    else
	    {
			TRAPD(err2, p = GetRightBorderL(iLeft.iY));
	        if(!err2 && iRight.iX > p.iX  && (Abs(iRight.iY - (iTop.iY+((iBottom.iY - iTop.iY)/2)))) > Abs((p.iY - (iTop.iY+((iBottom.iY - iTop.iY)/2)))))
	        	iRight = p;
	    }
	}

void CArea::DrawArea(CNokiaCVImage *aImage)
	{
	// create a bitmap to be used off-screen
	CFbsBitmap* offScreenBitmap = aImage->Bitmap();

	// create an off-screen device and context
	CGraphicsContext* bitmapContext=NULL;
	CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(offScreenBitmap);
	CleanupStack::PushL(bitmapDevice);
	User::LeaveIfError(bitmapDevice->CreateContext(bitmapContext));
	CleanupStack::PushL(bitmapContext);

	// draw area on the bitmap
	bitmapContext->SetBrushColor(KRgbYellow);
	bitmapContext->SetBrushStyle(CGraphicsContext::ESolidBrush);
	bitmapContext->DrawLine(iTop, iRight);
	bitmapContext->DrawLine(iRight, iBottom);
	bitmapContext->DrawLine(iBottom, iLeft);
	bitmapContext->DrawLine(iLeft, iTop);

	// cleanup
	CleanupStack::PopAndDestroy(2);
	}

void CArea::DrawRect(CNokiaCVImage *aImage)
	{
	// create a bitmap to be used off-screen
	CFbsBitmap* offScreenBitmap = aImage->Bitmap();

	// create an off-screen device and context
	CGraphicsContext* bitmapContext=NULL;
	CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(offScreenBitmap);
	CleanupStack::PushL(bitmapDevice);
	User::LeaveIfError(bitmapDevice->CreateContext(bitmapContext));
	CleanupStack::PushL(bitmapContext);

	// draw area on the bitmap
	bitmapContext->SetBrushColor(KRgbYellow);
	bitmapContext->SetBrushStyle(CGraphicsContext::ESolidBrush);
	TPoint a = TPoint(iLeft.iX, iBottom.iY);
	TPoint b = TPoint(iRight.iX, iBottom.iY);
	TPoint c = TPoint(iRight.iX, iTop.iY);
	TPoint d = TPoint(iLeft.iX, iTop.iY);
	bitmapContext->DrawLine(a, b);
	bitmapContext->DrawLine(b, c);
	bitmapContext->DrawLine(c, d);
	bitmapContext->DrawLine(d, a);

	// cleanup
	CleanupStack::PopAndDestroy(2);
	}

void CArea::DrawBorder(CNokiaCVImage *aImage)
	{
	// create a bitmap to be used off-screen
	CFbsBitmap* offScreenBitmap = aImage->Bitmap();

	// create an off-screen device and context
	CGraphicsContext* bitmapContext=NULL;
	CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(offScreenBitmap);
	CleanupStack::PushL(bitmapDevice);
	User::LeaveIfError(bitmapDevice->CreateContext(bitmapContext));
	CleanupStack::PushL(bitmapContext);

	// draw area on the bitmap
	bitmapContext->SetBrushColor(KRgbYellow);
	bitmapContext->SetBrushStyle(CGraphicsContext::ESolidBrush);
	
	for(TInt index = iTop.iY; index < iBottom.iY; index++)
	{
		TPoint p; 
		TRAPD(err, p= iBorders_left->FindL(index));
		if(!err)
			bitmapContext->DrawLine(p, TPoint(p.iX+1, p.iY));
	}
	for(TInt index = iTop.iY; index < iBottom.iY; index++)
	{
		TPoint p; 
		TRAPD(err, p= iBorders_right->FindL(index));
		if(!err)
			bitmapContext->DrawLine(p, TPoint(p.iX-1, p.iY));
	}
	

	// cleanup
	CleanupStack::PopAndDestroy(2);
	}
